package org.duang.captcha;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import javax.imageio.ImageIO;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.duang.kit.Encodes;

@WebServlet(name = "captchaServlet", urlPatterns = { "/aptcha/*" })
public class CaptchaServlet extends HttpServlet {

	private static final long serialVersionUID = 1L;
	private static int WIDTH = 80;
	private static int HEIGHT = 26;
	private static String[] strArr = {"3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H", "J", "K", "M", "N", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y"};
	private static String flag = "1";
	private static List<String> strList = new ArrayList<String>();
	private static Color[] colors = {Color.red, Color.blue, Color.green };
	private static final String randomCodeKey = "FastMvcCaptcha";
	
//	private static Logger logger = LoggerFactory.getLogger(CaptchaServlet.class);
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		String uri = request.getRequestURI(); 
		flag = uri.substring(uri.length()-1, uri.length());
		if("1".equals(flag)){
			WIDTH = 80;
			HEIGHT = 26;
		}else if("2".equals(flag)){
			WIDTH = CaptchaConst.WIDTH;
			HEIGHT = CaptchaConst.HEIGHT;
			String[] a = {"夜空中最亮的星", "蓝莲花", "义勇军进行曲", "五星红旗"} ;			
			List<String> list = CaptchaConst.CAPTCHA_MAP.get(a[new Random().nextInt(a.length)]);
			strList.clear();
			for(String str : list){
				for(int i=0; i<str.length();i++){
					strList.add(String.valueOf(str.charAt(i)));
				}
			}
		} else{
			return;
		}
		doPost(request, response);
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		BufferedImage image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
		String vCode = "";
		if("1".equals(flag))
			vCode = drawGraphic(image);
		else if ("2".equals(flag)){
			vCode = drawGraphic2(image);
		}
		vCode = Encodes.encodeHex(vCode.getBytes());
		Cookie cookie = new Cookie(randomCodeKey, vCode);
		cookie.setMaxAge(-1);
		cookie.setPath("/");
		response.addCookie(cookie);
		response.setHeader("Pragma","no-cache");
        response.setHeader("Cache-Control","no-cache");
        response.setDateHeader("Expires", 0);
        response.setContentType("image/jpeg");
        
        ServletOutputStream sos = null;
        try {
			sos = response.getOutputStream();
			ImageIO.write(image, "jpeg",sos);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
		finally {
			if (sos != null)
				try {sos.close();} catch (IOException e) {e.printStackTrace();}
		}
	}
	
	
	private String drawGraphic(BufferedImage image) {
		// 获取图形上下文
		Graphics g = image.createGraphics();
		// 生成随机类
		Random random = new Random();
		// 设定背景色
		g.setColor(getRandColor(200, 250));
		g.fillRect(0, 0, WIDTH, HEIGHT);
		// 设定字体
		g.setFont(new Font("Times New Roman", Font.PLAIN, 18));

		// 随机产生155条干扰线，使图象中的认证码不易被其它程序探测到
		g.setColor(getRandColor(160, 200));
		for (int i = 0; i < 155; i++) {
			int x = random.nextInt(WIDTH);
			int y = random.nextInt(HEIGHT);
			int xl = random.nextInt(12);
			int yl = random.nextInt(12);
			g.drawLine(x, y, x + xl, y + yl);
		}
		
		String sRand = "";
		// 取随机产生的认证码(4位数字)
		for (int i = 0; i < 4; i++) {
			String rand = String.valueOf(strArr[random.nextInt(strArr.length)]);
			sRand += rand;
			// 将认证码显示到图象中
			g.setColor(new Color(20 + random.nextInt(110), 20 + random.nextInt(110), 20 + random.nextInt(110)));
			// 调用函数出来的颜色相同，可能是因为种子太接近，所以只能直接生成
			g.drawString(rand, 16 * i + 11, 19);
		}
		// 图象生效
		g.dispose();
		return sRand.toLowerCase();
	}
	
	private String drawGraphic2(BufferedImage image) {
		Graphics g = image.createGraphics();
		Random random = new Random();
		g.setColor(getRandColor(200, 250));
		g.fillRect(0, 0, WIDTH, HEIGHT);
//		g.setFont(new Font("微软雅黑", Font.PLAIN, 18));
		g.setColor(getRandColor(160, 200));
		Graphics2D   g2d   = (Graphics2D)g; 
		g2d.setStroke(new BasicStroke(2.0f)); 
		for (int i = 0; i < 555; i++) {
			int x = random.nextInt(WIDTH);
			int y = random.nextInt(HEIGHT);
			int xl = random.nextInt(25);
			int yl = random.nextInt(25);
//			g2d.drawLine(x, y, x + xl, y + yl);
			//g.setColor(getRandColor(205, 255));
			g.drawLine(x, y, x + xl, y + yl);
		}
//		for (int i = 0; i < 255; i++) {
//			int x = random.nextInt(WIDTH);
//			int y = random.nextInt(HEIGHT);
//			int xl = random.nextInt(25);
//			int yl = random.nextInt(25);
//			g.setColor(getRandColor(105, 255));
//			g.fillOval(x, y, 5, 5);
//		}
		
		String sRand = "";
		int line = 0, point = 0;
		int size = strList.size();
		List<Integer> sRandList = new ArrayList<Integer>(4);
		for(int i=0; i<4; i++){
			int index = random.nextInt(size);
			if(sRandList.contains(index)){
				index = random.nextInt(size);
			}
			sRandList.add(index);
			
		}
		
		int lineCount = (strList.size() / 4);
		if(lineCount < 10) lineCount = 10; 

		String fontName = "";
		String osName = System.getProperty("os.name");
		if (osName.equals("Linux")) {
			fontName =  "Monospaced";
		} else {
			fontName = "微软雅黑";
		}
		
		Color color = colors[random.nextInt(colors.length)];
		for (int i = 0; i < size; i++) {
			String rand =  strList.get(i);			
			if((i%lineCount)==0){
				rand = "\r\n"+rand;
				line = line + 1; 
				point = 0;
			}
			if(sRandList.contains(i)){
				g.setFont(new Font(fontName, Font.BOLD, 20+random.nextInt(50)));
				g.setColor(color);
				sRand += rand;
			}else{
//				g.setColor(new Color(20 + random.nextInt(110), 20 + random.nextInt(110), 20 + random.nextInt(110)));
				g.setFont(new Font(fontName, Font.PLAIN, 20+random.nextInt(50)));
				g.setColor(new Color(105,105,105));
			}
						
			g.drawString(rand, (28 * point++) + 50, line * 60);
//			g.getFontMetrics().charsWidth(rand.toCharArray(), 1, 1);
		}
		g.dispose();
//		System.out.println(sRand);
		return sRand.toLowerCase();
	}
	
	/*
	 * 给定范围获得随机颜色
	 */
	private Color getRandColor(int fc, int bc) {
		Random random = new Random();
		if (fc > 255)
			fc = 255;
		if (bc > 255)
			bc = 255;
		int r = fc + random.nextInt(bc - fc);
		int g = fc + random.nextInt(bc - fc);
		int b = fc + random.nextInt(bc - fc);
		return new Color(r, g, b);
	}
}
